package com.izkml.mlyun.hotreload.service;

import cn.hutool.core.util.ObjectUtil;
import com.izkml.mlyun.hotreload.debug.connect.DebugConnector;
import com.izkml.mlyun.hotreload.debug.manager.BreakpointManager;
import com.izkml.mlyun.hotreload.debug.manager.WebSocketSessionManager;
import com.izkml.mlyun.hotreload.debug.protocol.Variable;
import com.izkml.mlyun.hotreload.model.debug.AddBreakpointsRequest;
import com.izkml.mlyun.hotreload.model.debug.EnableBreakpointsRequest;
import com.izkml.mlyun.hotreload.model.debug.RemoveBreakpointsRequest;
import com.izkml.mlyun.hotreload.model.debug.RunToSpecifiedLineRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;


/***
 * Debug调试服务类
 * @author zhangp
 * @date 2025/5/20 0020 14:43
 */
@Slf4j
@Service
public class DebugFacadeService {

    private final DebugConnector debugConnector;

    public DebugFacadeService() {
        this.debugConnector = DebugConnector.getInstance();
    }

    /**
     * 添加断点
     *
     * @return
     */
    public Boolean addBreakpoints(AddBreakpointsRequest request) {
        String sessionId = request.getSessionId();
        if (!WebSocketSessionManager.existsSessionId(sessionId)) {
            throw new RuntimeException("会话标识不存在");
        }
        String className = request.getClassName();
        if (!BreakpointManager.addBreakpoints(sessionId, className, request.getLines())) {
            throw new RuntimeException("该类正在被其他使用者调试！");
        }
        // 断点启用时才添加
        if (BreakpointManager.getEnable(sessionId)) {
            Integer[] lines = BreakpointManager.getBreakpointByClassName(className);
            debugConnector.overrideBreakpoints(className, lines);
        }
        return Boolean.TRUE;
    }

    /**
     * 取消断点
     *
     * @return
     */
    public Boolean removeBreakpoints(RemoveBreakpointsRequest request) {
        String sessionId = request.getSessionId();
        if (!WebSocketSessionManager.existsSessionId(sessionId)) {
            throw new RuntimeException("会话标识不存在");
        }
        BreakpointManager.removeBreakpoints(sessionId, request.getClassName(), request.getLines());
        // 断点启用时才去除
        if (BreakpointManager.getEnable(sessionId)) {
            Integer[] lines = BreakpointManager.getBreakpointByClassName(request.getClassName());
            String seq = debugConnector.overrideBreakpoints(request.getClassName(), lines);
        }
        return Boolean.TRUE;
    }

    /**
     * 覆盖断点
     *
     * @return
     */
    public Boolean overrideBreakpoints(AddBreakpointsRequest request) {
        String sessionId = request.getSessionId();
        if (!WebSocketSessionManager.existsSessionId(sessionId)) {
            throw new RuntimeException("会话标识不存在");
        }
        String className = request.getClassName();
        // 去除原来该类上的断点行
        Integer[] removeLines = BreakpointManager.getBreakpointByClassName(className);
        if(ObjectUtil.isNotEmpty(removeLines)) {
            BreakpointManager.removeBreakpoints(sessionId, className, removeLines);
        }
        // 添加新的断点行
        if (!BreakpointManager.addBreakpoints(sessionId, className, request.getLines())) {
            throw new RuntimeException("该类正在被其他使用者调试！");
        }
        // 断点启用时才发送添加命令
        if (BreakpointManager.getEnable(sessionId)) {
            debugConnector.overrideBreakpoints(request.getClassName(), request.getLines());
        }
        return Boolean.TRUE;
    }

    /**
     * 禁用/启用断点
     *
     * @return
     */
    public Boolean enableBreakpoints(EnableBreakpointsRequest request) {
        String sessionId = request.getSessionId();
        if (!WebSocketSessionManager.existsSessionId(sessionId)) {
            throw new RuntimeException("会话标识不存在");
        }
        if (request.getEnable()) {
            //启用
            Map<String, Set<Integer>> enableMap = BreakpointManager.getAllBreakpoint(sessionId);
            enableMap.entrySet().stream().forEach(x->{
                String className = x.getKey();
                Integer[] lines = ObjectUtil.isEmpty(x.getValue()) ? null : x.getValue().toArray(new Integer[x.getValue().size()]);
                String seq = debugConnector.overrideBreakpoints(className,lines);
            });
            BreakpointManager.enable(sessionId);
        } else {
            //禁用
            Map<String, Set<Integer>> disableMap = BreakpointManager.getAllBreakpoint(sessionId);
            disableMap.entrySet().stream().forEach(x->{
                String className = x.getKey();
                Integer[] lines = ObjectUtil.isEmpty(x.getValue()) ? null : x.getValue().toArray(new Integer[x.getValue().size()]);
                String seq = debugConnector.disableBreakpoints(className, lines);
            });
            BreakpointManager.disable(sessionId);
        }
        return Boolean.TRUE;
    }

    /**
     * 运行到指定代码行(下一代码段)
     *
     * @return
     */
    public Boolean runToSpecifiedLine(RunToSpecifiedLineRequest request) {
        if (!WebSocketSessionManager.existsSessionId(request.getSessionId())) {
            throw new RuntimeException("会话标识不存在");
        }
        String className = request.getClassName();
        // 断点启用时,获取这个类的所有断点
        Integer[] lines = null;
        if (BreakpointManager.getEnable(request.getSessionId())) {
            lines = BreakpointManager.getBreakpointByClassName(className);
        }
        // 添加一次性断点
        debugConnector.addOneTimeBreakpoint(className, lines, request.getLine());

        // 运行到下一断点代码行
        return this.runToNextBreakpointLine(request.getSessionId());
    }

    /**
     * 继续，运行到下一断点代码行
     *
     * @return
     */
    public Boolean runToNextBreakpointLine(String sessionId) {
        if (!WebSocketSessionManager.existsSessionId(sessionId)) {
            throw new RuntimeException("会话标识不存在");
        }
        String threadId = WebSocketSessionManager.getThreadId(sessionId);
        if (ObjectUtil.isEmpty(threadId)) {
            throw new RuntimeException("无暂停线程可执行！");
        }
        String seq = debugConnector.continueStep(Long.valueOf(threadId));
        WebSocketSessionManager.removeThreadId(sessionId);
        return Boolean.TRUE;
    }

    /**
     * 下一步（单步）
     *
     * @return
     */
    public Boolean nextStep(String sessionId) {
        if (!WebSocketSessionManager.existsSessionId(sessionId)) {
            throw new RuntimeException("会话标识不存在");
        }
        String threadId = WebSocketSessionManager.getThreadId(sessionId);
        if (ObjectUtil.isEmpty(threadId)) {
            throw new RuntimeException("无暂停线程可执行！");
        }
        String seq = debugConnector.nextStep(Long.valueOf(threadId));
        WebSocketSessionManager.removeThreadId(sessionId);
        return  Boolean.TRUE;
    }

    /**
     * 通过栈帧标识获取变量详细
     * @param stackFrameId
     * @return
     */
    public List<Variable> getVariablesByStackFrameId(Integer stackFrameId, String sessionId) {
        List<Variable> variables = new ArrayList<>();
        if (stackFrameId != null ) {
            String seq = debugConnector.scopes(stackFrameId,sessionId);
//            Responses.ScopesResponseBody scopesResponseBody = DebugUtil.getResponseBody(seq, Responses.ScopesResponseBody.class);
//            if (scopesResponseBody != null) {
//                Types.Scope scope = scopesResponseBody.scopes[0];
//                if (scope != null){
//                    int variablesReference = scope.variablesReference;
//                    // 查询变量列表
//                    variables = this.getVariablesByReference(variablesReference, sessionId);
//                }
//            }
        }
        return variables;
    }

    /**
     * 通过变量标识获取变量详细
     * @param variablesReference
     * @return
     */
    public List<Variable> getVariablesByReference(Integer variablesReference, String sessionId) {
        List<Variable> variables = null;
        if (variablesReference == null || variablesReference <= 0) {
            variables = new ArrayList<>();
        } else {
            String reqSeq = debugConnector.variables(variablesReference,sessionId);
//            // 获取所有变量
//            VariableHandler variableHandler = new VariableHandler();
//            variables = variableHandler.handle(variablesReference, sessionId);
        }
        return variables;
    }

    /**
     * 强制断开调试
     *
     * @return
     */
    public Boolean disconnect() {
        debugConnector.restart();
        return Boolean.TRUE;
    }

}
